package lex2

import (
	"strings"

	"gitee.com/u-language/u-language/ucom/enum"
)

// Token 单词标记 代表一个最小词法单元
type Token struct {
	//属性值
	Value string
	//种别码
	TYPE TokenType
}

// NewToken 创建标记
func NewToken(TYPE TokenType, value string) Token {
	return Token{
		TYPE:  TYPE,
		Value: value,
	}
}

func (t Token) String() string {
	var buf strings.Builder
	buf.Grow(40)
	buf.WriteString("\t{")
	buf.WriteString("type:")
	buf.WriteString(TokenStrMap[t.TYPE])
	buf.WriteString("\t value:")
	buf.WriteString(t.Value)
	buf.WriteString("}")
	return buf.String()
}

var hashMap [1 << 6]Token

func init() {
	addHashMap("var", VAR)
	addHashMap(enum.Func, FUNC)
	addHashMap("if", IF)
	addHashMap("else", ELSE)
	addHashMap("for", FOR)
	addHashMap("break", Break)
	addHashMap("continue", Continue)
	addHashMap("struct", Struct)
	addHashMap("interface", Interface)
	addHashMap("return", Return)
	addHashMap("goto", GOTO)
	addHashMap(enum.Const, Const)
	addHashMap(enum.Nil, Nil)
	addHashMap("package", Package)
	addHashMap(enum.Switch, Switch)
	addHashMap(enum.Case, Case)
	addHashMap(enum.Default, Default)
	addHashMap(enum.Method, Method)
	addHashMap(enum.AutoFree, AutoFree)
	addHashMap("and", AND)
	addHashMap("import", Import)
	addHashMap(enum.Enum, Enum)
	addHashMap("true", TRUE)
	addHashMap("false", FALSE)
}

func addHashMap(s string, kind TokenType) {
	hashMap[hash(s)] = NewToken(kind, s)
}

func hash(s string) uint {
	return (uint(s[0])<<4 ^ uint(s[1]) + uint(len(s))) & uint(len(hashMap)-1)
}

var (
	TokenStrMap = [...]string{
		No:              "no (没有表示)",
		NAME:            "name （符号）",
		ASSIGN:          "assign (赋值)",
		VAR:             "var (变量声明)",
		FUNC:            "func (函数声明)",
		ADD:             "add (加号)",
		SUB:             "sub (减号)",
		MUL:             "mul (乘号)",
		DIV:             "dlv (除号)",
		LBRACE:          "lbrace (左大括号)",
		RBRACE:          "rbrace (右大括号)",
		Int:             "int (整数)",
		FLOAT:           "float (浮点数)",
		NoEqual:         "no equal (不相等)",
		Equal:           "equal (相等)",
		Less:            "less (小于)",
		Greater:         "greater (大于)",
		TRUE:            "true",
		FALSE:           "false",
		IF:              "if",
		ELSE:            "else",
		FOR:             "for",
		Break:           "break",
		Continue:        "continue",
		Struct:          "struct",
		Interface:       "interface",
		LEA:             "lea (取地址)",
		OnlyLEA:         "onlylea (&)",
		MLC:             "multiline comment (多行注释)",
		String:          "string (字符串)",
		SEMICOLON:       "semicolon（分号）",
		Return:          "return (返回)",
		LPAREN:          "lparen (左小括号)",
		RPAREN:          "rparen (右小括号)",
		Comma:           "comma (逗号)",
		GOTO:            "goto",
		Colon:           "colon (冒号)",
		Remain:          "remainder (取余数)",
		Deref:           "dereference (解引用)",
		Const:           "const (常量)",
		Inc:             "Increment (自增)",
		Dec:             "Decrement (自减)",
		Nil:             "nil (指针的零值)",
		Package:         "package (包声明)",
		Switch:          "switch",
		Case:            "case",
		Default:         "default",
		Method:          "method (方法)",
		AutoFree:        "autofree (自动释放块)",
		SinLineComments: "Single-Line Comments (单行注释)",
		AND:             "AND (位与运算)",
		Or:              "Or (位或运算)",
		Xor:             "Xor (异或运算)",
		LogicAND:        "logic and (逻辑与)",
		LogicOr:         "logic or (逻辑或)",
		Import:          "import (导入)",
		Enum:            "enum (枚举)",
		EOF:             "结束",
		LBRACK:          "lbrack (左中括号)",
		RBRACK:          "rbrack (右中括号)",
		NewLine:         "新行",
		PERIOD:          "period (.)",
	}
)

// 标记类型
type TokenType int8

const (
	No TokenType = iota
	NAME
	ASSIGN
	VAR
	FUNC
	ADD
	SUB
	MUL
	DIV
	LBRACE
	RBRACE
	Int
	FLOAT
	NoEqual
	Equal
	Less
	Greater
	TRUE
	FALSE
	IF
	ELSE
	FOR
	Break
	Continue
	Struct
	Interface
	LEA
	OnlyLEA
	MLC //multiline comment
	String
	SEMICOLON //semicolon分号
	Return
	LPAREN //Left parenthesis
	RPAREN //right parenthesis
	Comma
	GOTO
	Colon
	Remain
	Deref //dereference
	Const
	Inc //Increment
	Dec //Decrement
	Nil
	Package
	Switch
	Case
	Default
	Method
	AutoFree
	SinLineComments //Single-Line Comments
	AND
	Or
	Xor
	LogicAND
	LogicOr
	Import
	Enum
	EOF
	LBRACK
	RBRACK
	NewLine
	PERIOD
)

func (t TokenType) String() string {
	return TokenStrMap[t]
}
